/**
 * @ClientMethodInterceptor.java  COPYRIGHT xiaojian
 * 
 * Created on 2017年1月6日 下午2:10:42
 */
package xj.toolkit.rpc.client;

import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.Map;

import javax.naming.NamingException;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.caucho.hessian.client.HessianProxyFactory;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;

import xj.toolkit.rpc.RpcException;
import xj.toolkit.rpc.naming.RpcNamingService;
import xj.toolkit.rpc.naming.RpcNode;

/**
 * 拦截器，从名称服务里面取得节点信息，通讯，调用远程方法。
 * 
 * @author <a href="mailto:cxj2000@gmail.com">xiaojian.cao</a>
 *
 */
public class ClientMethodInterceptor implements MethodInterceptor {

	private String serviceName = null;

	private Class<?> proxyInterface;

	private RpcNamingService namingService = null;

	private Map<RpcNode, Object> clientStubs = Maps.newConcurrentMap();

	HessianProxyFactory factory = new HessianProxyFactory();

	/**
	 * @param serviceName 服务名称。
	 * @param namingService 命名服务。
	 * @param proxyInterface 接口类。
	 */
	public ClientMethodInterceptor(String serviceName, RpcNamingService namingService, Class<?> proxyInterface) {
		Preconditions.checkArgument(serviceName != null);
		Preconditions.checkArgument(namingService != null);

		this.serviceName = serviceName;
		this.namingService = namingService;
		this.proxyInterface = proxyInterface;
		
		factory.setHessian2Request(true);
		factory.setHessian2Reply(true);

	}

	protected Object prepared() throws NamingException, RpcException {
		RpcNode node = namingService.randomGetNode(serviceName);
		
		if (node == null) {
			throw new NamingException("Cannot found node with name[" + serviceName + "].");
		}
		
		Object stub = clientStubs.get(node);
		if (stub != null) {
			return stub;
		}

		String url = "http://" + node.getIpAddress() + ":" + node.getPort() + "/" + serviceName;

		
		try {
			stub = factory.create(proxyInterface, url);
		} catch (MalformedURLException e) {
			throw new RpcException("Create stub fail. proxy[" + proxyInterface + "], serviceName[" + serviceName + "].",
					e);
		}
		
		clientStubs.put(node, stub);
		return stub;
	}
	

	/**
	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
	 */
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object stub = prepared();
		
		Method method = invocation.getMethod();
		Object[] args = invocation.getArguments();
		
		return method.invoke(stub, args);
	}

}
